/** @file  fim_proxy.c
 *  @brief fim
 *
 */

/*
//|----------------------------------------------------------------------------
//|                 SKY NETWORKS CONFIDENTIAL - COPYRIGHT 2016
//|----------------------------------------------------------------------------
//| The information contained herein is the property of SKY Networks and is
//| strictly confidential. Except as expressly authorized in writing by Sky
//| Networks, the holder shall keep all information contained herein confiden-
//| tial, shall disclose it only to its employees with a need to know, and
//| shall protect it, in whole or in part, from disclosure and dissemination
//| to third parties with the same degree of care it uses to protect its own
//| confidential information of like nature, but with no less than reasonable
//| care. Except expressly authorized in writing by Sky Networks, the holder
//| is granted no rights to use the information contained herein.
//|----------------------------------------------------------------------------
*/

/*
//|----------------------------------------------------------------------------
//| Flexelint
//|----------------------------------------------------------------------------
*/
/*lint -save */
/*lint +libclass(all) */

/*
//|----------------------------------------------------------------------------
//| Includes
//|----------------------------------------------------------------------------
*/
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include "msgid.h"
#include "fim.h"

static struct fim_options * mv = 0;

/*
//|--------------------------------------------------------------------------
//| Method     : fimp_genrx
//|--------------------------------------------------------------------------
*/
static int fimp_genrx
(
    void * buffer
)
{
    fd_set   readfds;
    struct timeval timeout;
    int rc;
    struct sockaddr_un remoteAddr;
    socklen_t partneraddrlen = sizeof(remoteAddr);

    FD_ZERO(&readfds);
    FD_SET(mv->socket,&readfds);

    timeout.tv_sec = 10;
    timeout.tv_usec = 0;
    rc = select(mv->socket+1,&readfds,0,0,&timeout);
    if(rc > 0 && FD_ISSET(mv->socket,&readfds))
    {
        return recvfrom( mv->socket, buffer, MSG_MAX_LEN, MSG_DONTWAIT,
                   (struct sockaddr*)((void *)&remoteAddr), &partneraddrlen );
    }
    else if(rc == 0)
    {
        printf("timeout\n");
    }
    else
    {
        printf("select failed with rc=%d errno=%s\n",rc,strerror(errno));
    }
    return -1;
}

/*
//|--------------------------------------------------------------------------
//| Method     : fimp_pstatus
//|--------------------------------------------------------------------------
*/
static void fimp_pstatus
(
    void * buffer
)
{
	/*lint --e{613} suppress "status" is not NULL check */
    struct fimStatusNt * status = buffer;
    status->max_size      = MSG_MAX_LEN;
    status->header.type   = FIM_STATUS;
    status->header.length = sizeof(struct fimStatusNt);

    if (fim_send_to(mv->socket,COMM_FIM,buffer,status->header.length, 1))
    {
        printf("fim_send_to failed\n");
        return;
    }

    while(fimp_genrx(buffer) > 0)
    {
      if(status->header.type != FIM_STATUS)
        break;

      printf("%s\n",status->statusString);
    }
}

/*
//|--------------------------------------------------------------------------
//| Method     : fim_main
//|--------------------------------------------------------------------------
*/
int fimp_main
(
    struct fim_options * in
)
{
    void *buffer;
    int rc = -1;
    struct msgHeaderNt * header;


    if (!in)
        return 0;

    mv=in;

    if (posix_memalign(&buffer,32,MSG_MAX_LEN) != 0)
    {
        printf("Could not allocate buffer <%d>: %s\n", errno, strerror(errno));
        return -1;
    }

    if ((mv->socket = fim_create_socket(COMM_FIM_P)) == 0)
    {
        printf("%s\n","Fim failed to initialize sockets\n");
        free(buffer);
        return -1;
    }

    if(mv->status)
    {
        fimp_pstatus(buffer);
    }

    /* Terminate is  mutually exclusive to all other options */
    header = buffer;
    if(mv->terminate)
    {
        header->type   = FIM_TERMINATE;
        header->length = sizeof(struct msgHeaderNt);
        if( fim_send_to(mv->socket,COMM_FIM,buffer,header->length, 1) )
        {
            printf("fim_send_to failed\n");
            rc = -1;
        }
        else
        {
            rc = fimp_genrx(buffer);
            if (rc < 0) printf("fimp_genrx failed\n");
        }
    }
    else
    {
        if(mv->dontkill)
        {
            header->type   = FIM_DONTKILL;
            header->length = sizeof(struct msgHeaderNt);
            if (fim_send_to(mv->socket,COMM_FIM,buffer,header->length, 1))
            {
                printf("fim_send_to failed\n");
                rc = -1;
            }
            else
            {
                rc = fimp_genrx(buffer);
                if (rc < 0)
                {
                    printf("fimp_genrx failed, error: %s\n", strerror(errno));
                }
            }
        }
        if(mv->run_level > 0)
        {
            struct fimRunLevelNt * run = buffer;
            run->runLevel  = mv->run_level;
            header->length = sizeof(struct fimRunLevelNt);
            header->type   = FIM_RUNLEVEL;
            if (fim_send_to(mv->socket,COMM_FIM,buffer,header->length, 1))
            {
                printf("fim_send_to failed\n");
                rc = -1;
            }
            else
            {
                rc = fimp_genrx(buffer);
                if (rc < 0)
                {
                  printf("fimp_genrx failed, error: %s\n", strerror(errno));
                }
            }
        }
    }
    free(buffer);
    close(mv->socket);
    return rc;
}
